#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/kfifo.h>


/* #define FH_I2C_DEBUG */

#define FH_I2C_DEBUG

#ifdef FH_I2C_DEBUG
#define PRINT_DBG(fmt, args...)  printk(fmt, ## args)
#else
#define PRINT_DBG(fmt, args...)  do { } while (0)
#endif

//#define SET_AS_MASTER

/*
 * Registers offset
 */
/*I2C*/
#define     REG_I2C_CON             (0x0000)
#define     REG_I2C_SAR             (0x0008)
#define     REG_I2C_DATA_CMD        (0x0010)
#define     REG_I2C_INTR_STAT       (0x002c)
#define     REG_I2C_INTR_MASK       (0x0030)
#define     REG_I2C_RAW_INTR_STAT   (0x0034)
#define     REG_I2C_RX_TL           (0x0038)
#define     REG_I2C_TX_TL           (0x003c)
#define     REG_I2C_CLR_INTR        (0x0040)
#define     REG_I2C_ENABLE          (0x006c)
#define     REG_I2C_STATUS          (0x0070)
#define     REG_I2C_TXFLR           (0x0074)
#define     REG_I2C_RXFLR           (0x0078)

#define DW_IC_INTR_NONE         0x0

#define DW_IC_CON		0x0
#define DW_IC_TAR		0x4
#define DW_IC_DATA_CMD		0x10
#define DW_IC_SS_SCL_HCNT	0x14
#define DW_IC_SS_SCL_LCNT	0x18
#define DW_IC_FS_SCL_HCNT	0x1c
#define DW_IC_FS_SCL_LCNT	0x20
#define DW_IC_INTR_STAT		0x2c
#define DW_IC_INTR_MASK		0x30
#define DW_IC_RAW_INTR_STAT	0x34
#define DW_IC_RX_TL		0x38
#define DW_IC_TX_TL		0x3c
#define DW_IC_CLR_INTR		0x40
#define DW_IC_CLR_RX_UNDER	0x44
#define DW_IC_CLR_RX_OVER	0x48
#define DW_IC_CLR_TX_OVER	0x4c
#define DW_IC_CLR_RD_REQ	0x50
#define DW_IC_CLR_TX_ABRT	0x54
#define DW_IC_CLR_RX_DONE	0x58
#define DW_IC_CLR_ACTIVITY	0x5c
#define DW_IC_CLR_STOP_DET	0x60
#define DW_IC_CLR_START_DET	0x64
#define DW_IC_CLR_GEN_CALL	0x68
#define DW_IC_ENABLE		0x6c
#define DW_IC_STATUS		0x70
#define DW_IC_TXFLR		0x74
#define DW_IC_RXFLR		0x78
#define DW_IC_COMP_PARAM_1	0xf4
#define DW_IC_TX_ABRT_SOURCE	0x80

#define DW_IC_CON_MASTER		0x1
#define DW_IC_CON_SPEED_STD		0x2
#define DW_IC_CON_SPEED_FAST		0x4
#define DW_IC_CON_10BITADDR_MASTER	0x10
#define DW_IC_CON_RESTART_EN		0x20
#define DW_IC_CON_SLAVE_DISABLE		0x40

#define DW_IC_INTR_RX_UNDER	0x001
#define DW_IC_INTR_RX_OVER	0x002
#define DW_IC_INTR_RX_FULL	0x004
#define DW_IC_INTR_TX_OVER	0x008
#define DW_IC_INTR_TX_EMPTY	0x010
#define DW_IC_INTR_RD_REQ	0x020
#define DW_IC_INTR_TX_ABRT	0x040
#define DW_IC_INTR_RX_DONE	0x080
#define DW_IC_INTR_ACTIVITY	0x100
#define DW_IC_INTR_STOP_DET	0x200
#define DW_IC_INTR_START_DET	0x400
#define DW_IC_INTR_GEN_CALL	0x800

#define DW_IC_INTR_DEFAULT_MASK		(DW_IC_INTR_RX_FULL | \
					 DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET | \
					 DW_IC_INTR_RD_REQ)

#define DW_IC_ERR_TX_ABRT	0x1

/*
 * status codes
 */
#define STATUS_IDLE			0x0
#define STATUS_WRITE_IN_PROGRESS	0x1
#define STATUS_READ_IN_PROGRESS		0x2

#define TIMEOUT			20 /* ms */




/* function Macro */
#define I2c_GetTxFifoDepth(base_addr)   (((readl(base_addr + \
		DW_IC_COMP_PARAM_1)>>16) & 0xff) + 1)

#define I2c_GetRxFifoDepth(base_addr)   (((readl(base_addr + \
		DW_IC_COMP_PARAM_1)>>8) & 0xff) + 1)

#define I2c_IsActiveSlv(base_addr)   (readl(base_addr + REG_I2C_STATUS)>>6 & 1)

#define I2c_DisEnable(base_addr)  writel(DISABLE, base_addr + REG_I2C_ENABLE)

#define I2c_Enable(base_addr)  writel(ENABLE, base_addr + REG_I2C_ENABLE)

#define I2c_Read(base_addr)   (readl(base_addr + REG_I2C_DATA_CMD)&0xff)

#define I2c_SetTxRxTl(base_addr, txtl, rxtl)    do {\
	writel(txtl, base_addr + REG_I2C_TX_TL);   \
	writel(rxtl, base_addr + REG_I2C_RX_TL);   \
	} while (0)

#define I2c_SetIntrMask(base_addr, mask)   writel(mask,\
		base_addr + REG_I2C_INTR_MASK)

#define I2c_SetCon(base_addr, config)  writel(config, base_addr + REG_I2C_CON)

#define I2c_ClrIntr(base_addr, mask)   readl(base_addr + mask)

#define I2c_GetRxFLR(base_addr)     (readl(base_addr + DW_IC_RXFLR)&0xff)

#define BUF_SIZE	256

#define IS_FULL 1

#define IS_EMPTY 2


enum BUS_STATUS {
	I2C_BUSY,
	I2C_IDLE
};
enum RESULT {
	SUCCESS,
	FAILURE
};
enum ENABLE_SET {
	DISABLE,
	ENABLE
};
enum SPEED_MODE {
	SSPEED = 1,
	FSPEED = 2,
	HSPEED = 3,
};

static struct kfifo receive_buf;

static struct kfifo send_buf;


/**
 * struct fh_i2c_dev - private i2c-designware data
 * @dev: driver model device node
 * @base: IO registers pointer
 * @cmd_complete: tx completion indicator
 * @lock: protect this struct and IO registers
 * @clk: input reference clock
 * @cmd_err: run time hadware error code
 * @msgs: points to an array of messages currently being transferred
 * @msgs_num: the number of elements in msgs
 * @msg_write_idx: the element index of the current tx message in the msgs
 *	array
 * @tx_buf_len: the length of the current tx buffer
 * @tx_buf: the current tx buffer
 * @msg_read_idx: the element index of the current rx message in the msgs
 *	array
 * @rx_buf_len: the length of the current rx buffer
 * @rx_buf: the current rx buffer
 * @msg_err: error status of the current transfer
 * @status: i2c master status, one of STATUS_*
 * @abort_source: copy of the TX_ABRT_SOURCE register
 * @irq: interrupt number for the i2c master
 * @adapter: i2c subsystem adapter node
 * @tx_fifo_depth: depth of the hardware tx fifo
 * @rx_fifo_depth: depth of the hardware rx fifo
 */
struct fh_i2c_dev {
	struct device		*dev;
	void __iomem		*base;
	struct completion	cmd_complete;
	struct mutex		lock;
	struct clk		*clk;
	int			cmd_err;
	struct i2c_msg		*msgs;
	int			msgs_num;
	int			msg_write_idx;
	u32			tx_buf_len;
	u8			*tx_buf;
	int			msg_read_idx;
	u32			rx_buf_len;
	u8			*rx_buf;
	int			msg_err;
	unsigned int		status;
	u32			abort_source;
	int			irq;
	struct i2c_adapter	adapter;
	unsigned int		tx_fifo_depth;
	unsigned int		rx_fifo_depth;
	char		isrname[24];
	int			id;
};

static int i2c_fh_wait_slave_not_active(struct fh_i2c_dev *dev)
{
	int timeout = 200;  /* 2000 us */

	while (I2c_IsActiveSlv(dev->base)) {
		if (timeout <= 0) {
			dev_warn(dev->dev, "timeout waiting for slave not active\n");
			return -ETIMEDOUT;
		}
		timeout--;
		udelay(10);
	}

	return 0;
}

/**
 * i2c_fh_slave_init() - initialize the designware i2c slave hardware
 * @dev: device private data
 *
 * This functions configures and enables the I2C slave.
 * This function is called during I2C init function, and in case of timeout at
 * run time.
 */
static void i2c_fh_slave_init(struct fh_i2c_dev *dev)
{
	u32 ic_con;

	i2c_fh_wait_slave_not_active(dev);
	I2c_DisEnable(dev->base);

	/* Configure Tx/Rx FIFO threshold levels */

	I2c_SetTxRxTl(dev->base, dev->tx_fifo_depth - 1, 0);
	/* configure the i2c slave */
	if(dev->id == 0)
		writel(0x45, dev->base + REG_I2C_SAR);
	else if(dev->id == 1)
		writel(0x46, dev->base + REG_I2C_SAR);
	else if(dev->id == 2)
		writel(0x47, dev->base + REG_I2C_SAR);
	else
	{
		PRINT_DBG( "i2c id error:%d", dev->id);
	}
	
	ic_con = 0;
	I2c_SetCon(dev->base, ic_con);
}

static u32 i2c_fh_read_clear_intrbits(struct fh_i2c_dev *dev)
{
	u32 stat;

	/*
	 * The IC_INTR_STAT register just indicates "enabled" interrupts.
	 * Ths unmasked raw version of interrupt status bits are available
	 * in the IC_RAW_INTR_STAT register.
	 *
	 * That is,
	 *   stat = readl(IC_INTR_STAT);
	 * equals to,
	 *   stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
	 *
	 * The raw version might be useful for debugging purposes.
	 */
	stat = readl(dev->base + DW_IC_INTR_STAT);

	/*
	 * Do not use the IC_CLR_INTR register to clear interrupts, or
	 * you'll miss some interrupts, triggered during the period from
	 * readl(IC_INTR_STAT) to readl(IC_CLR_INTR).
	 *
	 * Instead, use the separately-prepared IC_CLR_* registers.
	 */
	if (stat & DW_IC_INTR_RX_UNDER)
		I2c_ClrIntr(dev->base, DW_IC_CLR_RX_UNDER);
	if (stat & DW_IC_INTR_RX_OVER)
		I2c_ClrIntr(dev->base, DW_IC_CLR_RX_OVER);
	if (stat & DW_IC_INTR_TX_OVER)
		I2c_ClrIntr(dev->base, DW_IC_CLR_TX_OVER);
	if (stat & DW_IC_INTR_TX_ABRT) {
		/*
		 * The IC_TX_ABRT_SOURCE register is cleared whenever
		 * the IC_CLR_TX_ABRT is read.  Preserve it beforehand.
		 */
		dev->abort_source = readl(dev->base + DW_IC_TX_ABRT_SOURCE);
		I2c_ClrIntr(dev->base, DW_IC_CLR_TX_ABRT);
	}
	if (stat & DW_IC_INTR_RX_DONE)
		I2c_ClrIntr(dev->base, DW_IC_CLR_RX_DONE);
	if (stat & DW_IC_INTR_ACTIVITY)
		I2c_ClrIntr(dev->base, DW_IC_CLR_ACTIVITY);
	if (stat & DW_IC_INTR_STOP_DET)
		I2c_ClrIntr(dev->base, DW_IC_CLR_STOP_DET);
	if (stat & DW_IC_INTR_START_DET)
		I2c_ClrIntr(dev->base, DW_IC_CLR_START_DET);
	if (stat & DW_IC_INTR_GEN_CALL)
		I2c_ClrIntr(dev->base, DW_IC_CLR_GEN_CALL);

	return stat;
}

static void i2c_fh_read(struct fh_i2c_dev *dev)
{
	PRINT_DBG("read to read_buf\n");
	u32 wait2read_num = I2c_GetRxFLR(dev->base);
	u8 read_from_reg;
	int read_buf = kfifo_avail(&receive_buf);
	int read_num = (wait2read_num < read_buf) ? wait2read_num : read_buf;
	while(read_num > 0)
	{
		read_from_reg = I2c_Read(dev->base);
		PRINT_DBG("Read:0x%x\n", read_from_reg);
		kfifo_in(&receive_buf, &read_from_reg, 1);
		read_num--;
	}
	return;

}

static void i2c_fh_read_from_master(struct i2c_msg *msgs)
{
	u8 *buf;
	u8 show;
	u8 show_buf;
	u32 len;
	int i = 0;

	buf = msgs->buf;
	len = msgs->len;
	
	for (; len > 0 ; len--){
		if (kfifo_is_empty(&receive_buf) == 0){
			kfifo_out(&receive_buf, &show_buf, 1);
			show = show_buf & 0xff;
			*buf++ = show;
			i++;
		}
		else
		*buf++ = 0;
	}
	PRINT_DBG("i2c_fh_read, len: %d, buf[0]: 0x%x\n",
			i, 
			msgs->buf[0]);

	return;
}

static void i2c_fh_send_to_master(struct i2c_msg *msgs)
{
	u8 *buf;
	u8 send_to_reg;

	int sendbuf_res = kfifo_avail(&send_buf);
	int wait2send_num = msgs->len;
	int send_num = (sendbuf_res < wait2send_num) ? sendbuf_res : wait2send_num;
	buf = msgs->buf;
	
	while(send_num > 0)
	{
		send_to_reg = *buf++;
		PRINT_DBG("Send_buf:0x%x\n", send_to_reg);
		kfifo_in(&send_buf, &send_to_reg, 1);
		send_num--;
	}
	return;
}

static void i2c_fh_write(struct fh_i2c_dev *dev)
{
	u8 buf;
	u8 write_buf;
	if(kfifo_is_empty(&send_buf)){
		pr_err("i2c send error: empty\n");
		writel(0x00 & ~(1 << 8), dev->base + DW_IC_DATA_CMD);
		I2c_ClrIntr(dev->base, DW_IC_CLR_RD_REQ);
		return;
	}
	kfifo_out(&send_buf, &write_buf, 1);
	buf = write_buf & 0xff;
	PRINT_DBG( "send:0x%x\n", buf & ~(1 << 8));
	writel(buf & ~(1 << 8), dev->base + DW_IC_DATA_CMD);
	I2c_ClrIntr(dev->base, DW_IC_CLR_RD_REQ);
	return ;
}


/*
 * Interrupt service routine. This gets called whenever an I2C interrupt
 * occurs.
 */
static irqreturn_t i2c_fh_isr(int this_irq, void *dev_id)
{
	struct fh_i2c_dev *dev = dev_id;
	u32 stat;

	stat = i2c_fh_read_clear_intrbits(dev);
	PRINT_DBG( "\n intterrupt:ENTER I2C ISR HANDLER\n");
	PRINT_DBG( "-----------i2c, %s: stat=0x%x\n", __func__, stat);
	if (stat & DW_IC_INTR_TX_ABRT) {
		PRINT_DBG( "DW_IC_INTR_TX_ABRT\n");
		dev->cmd_err |= DW_IC_ERR_TX_ABRT;
		dev->status = STATUS_IDLE;

		/*
		 * Anytime TX_ABRT is set, the contents of the tx/rx
		 * buffers are flushed.  Make sure to skip them.
		 */
		I2c_SetIntrMask(dev->base, DW_IC_INTR_NONE);
		goto tx_aborted;
	}

	if (stat & DW_IC_INTR_RX_FULL) {
		PRINT_DBG( "i2c_fh_read\n");
		i2c_fh_read(dev);
		PRINT_DBG( "read end\n");
	}
	if (stat & DW_IC_INTR_RD_REQ) {
		PRINT_DBG( "i2c_fh_RD_REQ\n");
		i2c_fh_write(dev);
		PRINT_DBG( "write end\n");
	}

	/*
	 * No need to modify or disable the interrupt mask here.
	 * i2c_fh_xfer_msg() will take care of it according to
	 * the current transmit status.
	 */

tx_aborted:
	if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
		complete(&dev->cmd_complete);

	return IRQ_HANDLED;
}

static u32 i2c_fh_func(struct i2c_adapter *adap)
{
	return	I2C_FUNC_I2C |
		I2C_FUNC_SLAVE;
}

int fh_reg_slave(struct i2c_client *client)
{
	struct fh_i2c_dev *dev = i2c_get_adapdata(client->adapter);
	PRINT_DBG("I2C SLAVE START\n");
		/* Enable the adapter */
	I2c_Enable(dev->base);

	/* Enable interrupts */
	I2c_SetIntrMask(dev->base, DW_IC_INTR_DEFAULT_MASK);
	return 0;
}

int fh_unreg_slave(struct i2c_client *client)
{
	struct fh_i2c_dev *dev = i2c_get_adapdata(client->adapter);
	PRINT_DBG("I2C SLAVE END\n");
		/* Disable the adapter */
	I2c_DisEnable(dev->base);

	/* Disable interrupts */
	I2c_SetIntrMask(dev->base, DW_IC_INTR_NONE);
	return 0;
}

static int __i2c_fh_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msgs,
				 struct fh_i2c_dev *dev)
{
	__u16 flags = msgs->flags;

	PRINT_DBG("-------i2c", __func__);

	mutex_lock(&dev->lock);

	if (flags & I2C_M_RD) {
		PRINT_DBG("READ_FROM_MASTER");
		i2c_fh_read_from_master(msgs);
	} else {
		PRINT_DBG("SEND_TO_MASTER");
		i2c_fh_send_to_master(msgs);
	}
	PRINT_DBG("buf: 0x%x\n", msgs->buf[0]);
	mutex_unlock(&dev->lock);
}

static int i2c_fh_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
	struct fh_i2c_dev *dev = i2c_get_adapdata(adap);
	int i;
	int ret;

	dev->cmd_err = 0;
	dev->msg_err = 0;
	dev->status = STATUS_IDLE;
	dev->abort_source = 0;

	for (i = 0; i < num; i++) {
		ret = __i2c_fh_xfer_msg(adap, &msgs[i], dev);
		if(ret < 0)
			return ret;
	}

	return num;
}

static struct i2c_algorithm i2c_fh_algo = {
	.reg_slave = fh_reg_slave,
	.unreg_slave = fh_unreg_slave,
	.functionality = i2c_fh_func,
	.master_xfer = i2c_fh_xfer_msg,
};

static int fh_i2c_slave_probe(struct platform_device *pdev)
{
	struct fh_i2c_dev *dev;
	struct i2c_adapter *adap;
	struct resource *mem;
	int r;
	int id = 0;
	int err = 0;
	char clkname[24] = {0};

	r = kfifo_alloc(&receive_buf, BUF_SIZE, GFP_KERNEL);
	if(r){
		r = -ENOMEM;
		goto err_return;
	}

	r = kfifo_alloc(&send_buf, BUF_SIZE, GFP_KERNEL);
	if(r){
		r = -ENOMEM;
		goto err_return;
	}
	

	dev = kzalloc(sizeof(struct fh_i2c_dev), GFP_KERNEL);
	if(!dev){
		r = -ENOMEM;
		goto err_free_kfifo;
	}

	id = pdev->id;
	dev->id = pdev->id;
	PRINT_DBG( "i2c-%d initialize as slave start\n", pdev->id);

	snprintf(clkname, sizeof(clkname), "i2c%d_clk", id);
	dev->clk = clk_get(NULL, clkname);
	snprintf(dev->isrname, sizeof(dev->isrname), "i2c-%d", id);

	if (IS_ERR(dev->clk)) {
		r = -ENODEV;
		goto err_free_mem;
	}
	clk_prepare_enable(dev->clk);

	init_completion(&dev->cmd_complete);
	mutex_init(&dev->lock);
	dev->dev = get_device(&pdev->dev);
	platform_set_drvdata(pdev, dev);
	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!mem) {
		dev_err(&pdev->dev, "no mem resource?\n");
		r = -EINVAL;
		goto err_unuse_clocks;
	}
	dev->irq = irq_create_mapping(NULL, platform_get_irq(pdev, 0));
	dev->base = ioremap(mem->start, resource_size(mem));

	if (dev->base == NULL) {
		dev_err(&pdev->dev, "failure mapping io resources\n");
		r = -ENOMEM;
		goto err_unuse_clocks;
	}
	{
		dev->tx_fifo_depth = I2c_GetTxFifoDepth(dev->base);
		dev->rx_fifo_depth = I2c_GetRxFifoDepth(dev->base);
	}

	i2c_fh_slave_init(dev);

	PRINT_DBG( "\ntx fifo depth: %d, rx fifo depth: %d\n",
		dev->tx_fifo_depth, dev->rx_fifo_depth);
	
	I2c_SetIntrMask(dev->base, DW_IC_INTR_NONE); /* disable IRQ */

	if (dev->irq < 0) {
		dev_err(&pdev->dev, "no irq resource?\n");
		r = -ENXIO;
		goto err_iounmap;
	}

	err = request_irq(dev->irq, i2c_fh_isr,
						IRQF_SHARED, dev->isrname, dev);

	if (err) {
		dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
		r = -ENXIO;
		goto err_iounmap;
	}

	adap = &dev->adapter;
	i2c_set_adapdata(adap, dev);
	adap->owner = THIS_MODULE;
	adap->class = I2C_CLASS_HWMON;
	strlcpy(adap->name, "FH I2C adapter",
			sizeof(adap->name));
	adap->algo = &i2c_fh_algo;
	adap->dev.parent = &pdev->dev;

	adap->nr = id;

	r = i2c_add_numbered_adapter(adap);

	if (r) {
		dev_err(&pdev->dev, "failure adding adapter\n");
		goto err_free_irq;
	}


	PRINT_DBG( "\t%s - (dev. name: %s id: %d, IRQ #%d\n"
		   "\t\tIO base addr: 0x%p)\n", "I2C", pdev->name,
		   id, dev->irq, dev->base);

	I2c_Enable(dev->base);

	/* Enable interrupts */
	I2c_SetIntrMask(dev->base, DW_IC_INTR_DEFAULT_MASK);

	return 0;

err_free_irq:
	free_irq(dev->irq, dev);
err_iounmap:
	iounmap(dev->base);
err_unuse_clocks:
	clk_disable_unprepare(dev->clk);
	clk_put(dev->clk);
	dev->clk = NULL;
err_free_mem:
	put_device(&pdev->dev);
	kfree(dev);
err_free_kfifo:
	kfifo_free(&receive_buf);
	kfifo_free(&send_buf);
err_return:
	return r;
}

static int __exit fh_i2c_remove(struct platform_device *pdev)
{
	struct fh_i2c_dev *dev = platform_get_drvdata(pdev);

	put_device(&pdev->dev);

	clk_disable_unprepare(dev->clk);
	clk_put(dev->clk);

	dev->clk = NULL;
	i2c_fh_wait_slave_not_active(dev);
	writel(0, dev->base + DW_IC_ENABLE);
	free_irq(dev->irq, dev);
	kfree(dev);

	return 0;
}

static struct platform_driver fh_i2c_slave_driver = {
	.driver		= {
		.name	= "fh_i2c_slave",
		.owner	= THIS_MODULE,
	},
	.probe		= fh_i2c_slave_probe,
	.remove		= __exit_p(fh_i2c_remove),
};

static int __init fh_i2c_slave_init(void)
{
	return platform_driver_register(&fh_i2c_slave_driver);
}

static void __exit fh_i2c_slave_exit(void)
{

	platform_driver_unregister(&fh_i2c_slave_driver);

}

module_init(fh_i2c_slave_init);
module_exit(fh_i2c_slave_exit);


MODULE_AUTHOR("fullhan");
MODULE_ALIAS("platform:fh");
MODULE_DESCRIPTION("fullhan i2c driver");
MODULE_LICENSE("GPL");